const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
	constructor(executor) {
		try {
			executor(this.resolve, this.reject)
		} catch (error) {
			this.reject(error)
		}
	}

	// promise 状态
	status = PENDING
	//保存成功之后的返回值
	value = undefined
	//保存失败的原因
	reason = undefined
	// 成功回调函数
	successCallback = []
	// 失败回调函数
	failCallback = []

	// 使用箭头函数绑定this
	resolve = (value) => {
		if (this.status != PENDING) return
		this.status = FULFILLED
		this.value = value
		// 判断成功回调是否存在，如果存在就调用
		// this.successCallback && this.successCallback(this.value)
		// 现在回调函数是一个数组
		while (this.successCallback.length) {
			let callback = this.successCallback.shift()
			callback()
		}
	}

	reject = (reason) => {
		if (this.status != PENDING) return
		this.status = REJECTED
		this.reason = reason
		// 判断失败回调是否存在，如果存在就调用
		// this.successCallback && this.successCallback(this.value)
		// 现在回调函数是一个数组
		while (this.failCallback.length) {
			let callback = this.failCallback.shift()
			callback()
		}
	}

	then(successCallback, failCallback) {
		// 判断传入的回调是不是函数
		successCallback =
			typeof successCallback === 'function'
				? successCallback
				: (value) => value
		failCallback =
			typeof failCallback === 'function'
				? failCallback
				: (reason) => reason

		let promiseReturned = new MyPromise((resolve, reject) => {
			// 判断状态，如果已经变化了就立即调用回调函数
			if (this.status === FULFILLED) {
				setTimeout(() => {
					try {
						let x = successCallback(this.value)
						// 检查x是否是也是一个MyPromise对象
						resolvePromise(promiseReturned, x, resolve, reject)
					} catch (error) {
						reject(error)
					}
				}, 0)
			} else if (this.status === REJECTED) {
				setTimeout(() => {
					try {
						let x = failCallback(this.reason)
						// 检查x是否是也是一个MyPromise对象
						resolvePromise(promiseReturned, x, resolve, reject)
					} catch (error) {
						reject(error)
					}
				}, 0)
			} else {
				// 等待，状态还没有变化
				// 将成功和失败的回调函数储存起来
				this.successCallback.push(() => {
					setTimeout(() => {
						try {
							let x = successCallback(this.value)
							// 检查x是否是也是一个MyPromise对象
							resolvePromise(promiseReturned, x, resolve, reject)
						} catch (error) {
							reject(error)
						}
					}, 0)
				})
				this.failCallback.push(() => {
					setTimeout(() => {
						try {
							let x = failCallback(this.reason)
							// 检查x是否是也是一个MyPromise对象
							resolvePromise(promiseReturned, x, resolve, reject)
						} catch (error) {
							reject(error)
						}
					}, 0)
				})
			}
		})
		return promiseReturned
	}

	// finally方法不再会return新的值，因为到这里就应该结束了
	// fianlly方法会在最后返回传入的值
	// 但是如果callback有异步操作，finally应该等待其完成
	finally(callback) {
		return this.then(
			(value) => {
				MyPromise.resolve(callback()).then(() => value)
			},
			(reason) => {
				MyPromise.resolve(callback()).then(() => {
					throw reason
				})
			}
		)
	}

	catch(failCallback) {
		return this.then(undefined, failCallback)
	}

	static resolve(value) {
		if (value instanceof MyPromise) return value
		return new MyPromise((resolve) => resolve(value))
	}

	// 全部Promise都返回才结束
	static all(array) {
		return new MyPromise((resolve, reject) => {
			let result = []
			let count = 0
			// 需要使用一个函数来记录每个Promise返回的情况
			function addData(key, value) {
				result[key] = value
				//! 不能使用result.length === array.length来判断，因为有可能先填充后面的元素，length是不准确的
				count += 1
				if (count === array.length) {
					resolve(result)
				}
			}

			array.map((promise, index) => {
				if (promise instanceof MyPromise) {
					// Prmoise对象
					promise.then(
						(value) => addData(index, value),
						(reason) => reject(reason)
					)
				} else {
					// 普通值
					addData(index, promise)
				}
			})
		})
	}

	// 只要有一个Promise返回即可，所以任意Promise都可以触发resolve
	static race(array) {
		return new MyPromise((resolve, reject) => {
			array.map((promise) => {
				if (promise instanceof MyPromise) {
					promise
						.then((value) => resolve(value))
						.catch((error) => reject(error))
				} else {
					// 不是Promise对象，直接返回即可
					resolve(promise)
				}
			})
		})
	}
}

function resolvePromise(promiseReturned, x, resolve, reject) {
	//! 不允许返回自身 会造成无限then嵌套
	if (promiseReturned === x) {
		reject(new TypeError('Chaining cycle detected for promise'))
	}
	if (x instanceof MyPromise) {
		// 是一个 MyPromise对象
		x.then(resolve, reject)
	} else {
		// 普通值
		resolve(x)
	}
}

export default MyPromise
